# 登录并上传软件新版本到更新服务器(https://update.forensix.cn)
fs = require 'fs'
crypto = require 'crypto'
request = require 'request'

update_server = process.env.UPDATE_SERVER || 'https://update.forensix.cn'
auth_server = process.env.AUTH_SERVER || 'https://account.forensix.cn'

class UpdateService
  constructor: (@_clientId, @_clientSecret)->
    @_jar = request.jar()

  login: (username, password, cb)->
    # 获取state参数
    await request.get update_server + '/auth/honglian', {jar: @_jar, followRedirect: false}, defer err, resp, body
    return cb err if err
    state = resp.headers.location?.split('&state=')[1] || ''

    form = {
      'username': username,
      'password': password,
      'client_id': 'UPDATESERVICE',
      'redirect_uri': update_server + '/auth/honglian/callback',
      'grant_type': 'password',
      'scope': 'profile',
      'response_type': 'code'
    }

    await request.post auth_server + '/oauth/login/authorise', {form, jar: @_jar}, defer err, resp, body
    return cb err if err

    try
      body = JSON.parse body
    catch e
      return cb e

    await request.get update_server + '/auth/honglian/callback?code=' + body['authCode']['authorizationCode'] + '&state=' + state, {jar: @_jar}, defer err, resp, body
    return cb err if err

    if resp.statusCode != 200
      console.log body
      return cb '登录更新服务失败！'
    else
      console.log '登录更新服务成功'
      cb null

  # 上传某个产品的新版本
  # param.client_name [字符串] 产品英文名，需与用户中心应用属性一致
  # param.version [字符串] 新版本号
  # param.description [字符串] 新版本描述信息
  # param.path [字符串] 本地文件路径
  upload: (param, cb)->
    formData =
      software: param.client_name
      version: param.version
      description: param.description
      files: [fs.createReadStream(param.path)]

    await request.post update_server + '/upload/', {formData, jar: @_jar}, defer err, resp, body
    return cb err if err
    if resp.statusCode != 302 # 正常上传成功后会重定向
      matches = body.match /<h4>失败原因：(.*)<\/h4>/
      return cb(if matches then matches[1] else body)

    console.log '上传新版本成功'
    cb null

  # 上传一个或多个组件
  uploadComponents: (components, cb)->
    formData =
      client_id: @_clientId
      client_secret: @_clientSecret
      compsInfo: []
      files: []

    for comp in components
      await @md5File comp.path, defer err, md5
      return cb err if err
      comp.md5 = md5
      formData.compsInfo.push JSON.stringify(comp)
      formData.files.push fs.createReadStream(comp.path)

    await request.post update_server + '/api/components/', {formData, jar: @_jar}, defer err, resp, body
    return cb err if err
    if resp.statusCode != 200
      matches = body.match /<h4>失败原因：(.*)<\/h4>/
      return cb(if matches then matches[1] else body)

    console.log '上传组件成功'
    cb null

  md5File: (filename, cb) ->
    output = crypto.createHash('md5')
    input = fs.createReadStream(filename)
    input.on 'error', cb
    output.once 'readable', ->
      cb null, output.read().toString('hex')
    input.pipe output

module.exports = UpdateService
